package client;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.swing.BorderFactory;
import javax.swing.SwingUtilities;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;

import server.ImageUpload;
import server.UploadService;

/** This class defines the Graphical User Interface that allows a user to compress,
 *  select and upload an image
 * 	
 * 	@author Daniel Hutchinson
 *	@version 1.0
 */
public class UploadGUI extends JFrame implements ActionListener{
	private JPanel main, images, metaData, fileBrowser;	/* Top level panels */
	/* Meta Panel Sub Panels */
	private JPanel userMetaData, autoMetaData;
	/* Meta Data input */
	private JTextField imageTitleInput, imageKeywordsInput, imageDescription;
	private JTextField imageFileSizeInput, imageDimensionInput, imageBitDepthInput;
	private JCheckBox imageHasRoyalties;
	
	/* File Browser Input */
	private JTextField filePath;
	private JButton openFile, browseForFile;
	private JFileChooser fileBrowsing;
	private File currentFile;
	
	/* Image preview panels */
	private JPanel mainImage, previewPanels;
	private JPanel mainImagePanel, preview1Panel, preview2Panel, preview3Panel, preview4Panel;
	private JLabel originalLabel, lowLabel, goodLabel, fineLabel, proLabel;
	private PlanarImage currentImage = JAI.create("fileload", "img/PlaceHolder.jpg");
	private ImageViewer mainPreview, preview1, preview2, preview3, preview4;
	private JRadioButton lowRadio, goodRadio, fineRadio, proRadio, mainHide;
	private ButtonGroup buttonGroup;
	
	/* Server variables */
	private String serverName;
	
	/* Other variables */
	private final int NUMCOLUMNS = 20;
	
	/** This constructor creates a new instance of the Uploading GUI */
	public UploadGUI(File configFile){
		super("Image Conversion Tool");
		
		/* Create instances of variables */
		main = new JPanel();
		images = new JPanel();
		metaData = new JPanel();
		fileBrowser = new JPanel();
		
		userMetaData = new JPanel();
		autoMetaData = new JPanel();
		
		originalLabel = new JLabel("Original");
		lowLabel = new JLabel("Low");
		goodLabel = new JLabel("Good");
		fineLabel = new JLabel("Fine");
		proLabel = new JLabel("Pro");
		
		lowRadio = new JRadioButton("Low");
		lowRadio.setSelected(true);
		goodRadio = new JRadioButton("Good");
		fineRadio = new JRadioButton("Fine");
		proRadio = new JRadioButton("Pro");
		mainHide = new JRadioButton();
		mainHide.setVisible(false);
		buttonGroup = new ButtonGroup();
		
		buttonGroup.add(lowRadio);
		buttonGroup.add(goodRadio);
		buttonGroup.add(fineRadio);
		buttonGroup.add(proRadio);
		buttonGroup.add(mainHide);
		
		mainImagePanel = new JPanel();
		mainImagePanel.setLayout(new BorderLayout());
		mainImagePanel.add(mainHide, BorderLayout.SOUTH);
		preview1Panel = new JPanel();
		preview1Panel.setLayout(new BorderLayout());
		preview1Panel.add(lowRadio, BorderLayout.SOUTH);
		preview2Panel = new JPanel();
		preview2Panel.setLayout(new BorderLayout());
		preview2Panel.add(goodRadio, BorderLayout.SOUTH);
		preview3Panel = new JPanel();
		preview3Panel.setLayout(new BorderLayout());
		preview3Panel.add(fineRadio, BorderLayout.SOUTH);
		preview4Panel = new JPanel();
		preview4Panel.setLayout(new BorderLayout());
		preview4Panel.add(proRadio, BorderLayout.SOUTH);
		
		imageTitleInput = new JTextField(NUMCOLUMNS);
		imageKeywordsInput = new JTextField(NUMCOLUMNS);
		imageDescription = new JTextField(NUMCOLUMNS);
		
		imageFileSizeInput = new JTextField(NUMCOLUMNS);
		imageDimensionInput = new JTextField(NUMCOLUMNS);
		imageBitDepthInput = new JTextField(NUMCOLUMNS);
		
		imageHasRoyalties = new JCheckBox();
		
		filePath = new JTextField(NUMCOLUMNS);
		openFile = new JButton("Open");
		browseForFile = new JButton("Browse");
		
		mainImage = new JPanel();
		previewPanels = new JPanel();
		
		mainPreview = new ImageViewer(300, 300, this, true, mainImagePanel, originalLabel, mainHide);
		preview1 = new ImageViewer(145, 145, this, false, preview1Panel, lowLabel, lowRadio);
		preview2 = new ImageViewer(145, 145, this, false, preview2Panel, goodLabel, goodRadio);
		preview3 = new ImageViewer(145, 145, this, false, preview3Panel, fineLabel, fineRadio);
		preview4 = new ImageViewer(145, 145, this, false, preview4Panel, proLabel, proRadio);
		
		mainImagePanel.add(mainPreview, BorderLayout.EAST);
		mainImagePanel.add(originalLabel, BorderLayout.NORTH);
		preview1Panel.add(preview1, BorderLayout.EAST);
		preview1Panel.add(lowLabel, BorderLayout.NORTH);
		preview2Panel.add(preview2, BorderLayout.EAST);
		preview2Panel.add(goodLabel, BorderLayout.NORTH);
		preview3Panel.add(preview3, BorderLayout.EAST);
		preview3Panel.add(fineLabel, BorderLayout.NORTH);
		preview4Panel.add(preview4, BorderLayout.EAST);
		preview4Panel.add(proLabel, BorderLayout.NORTH);
		
		/* Add Image Fields */
		//images.setBorder(BorderFactory.createTitledBorder("Image Preview"));
		images.setLayout(new BorderLayout());
		
		mainImage.setLayout(new FlowLayout());
		mainImage.add(mainImagePanel);
		
		previewPanels.setLayout(new FlowLayout());
		previewPanels.add(preview1Panel);
		previewPanels.add(preview2Panel);
		previewPanels.add(preview3Panel);
		previewPanels.add(preview4Panel);
		
		mainPreview.displayImage(JAI.create("fileload", "img/PlaceHolder.jpg").getAsBufferedImage());
		
		images.add(mainImage, BorderLayout.NORTH);
		images.add(previewPanels, BorderLayout.SOUTH);
		
		/* Add File Browsing Fields */
		fileBrowser.setBorder(BorderFactory.createTitledBorder("File Browser"));
		fileBrowser.setLayout(new GridLayout(1, 4));
		
		openFile.addActionListener(this);
		browseForFile.addActionListener(this);
		
		fileBrowser.add(new JLabel("File: "));
		fileBrowser.add(filePath);
		fileBrowser.add(openFile);
		fileBrowser.add(browseForFile);
		
		fileBrowsing = new JFileChooser();
		fileBrowsing.setFileFilter(new ImageFileFilter());
		
		currentFile = null;
		
		/* Add Fields to Meta Data Input */
		userMetaData.setBorder(BorderFactory.createTitledBorder("Image Information"));
		autoMetaData.setBorder(BorderFactory.createTitledBorder("Image Details"));
		
		userMetaData.setLayout(new GridLayout(3,2));
		userMetaData.add(new JLabel("Title: "));
		userMetaData.add(imageTitleInput);
		
		userMetaData.add(new JLabel("Keywords: "));
		userMetaData.add(imageKeywordsInput);
		
		userMetaData.add(new JLabel("Description: "));
		userMetaData.add(imageDescription);
		
		autoMetaData.setLayout(new GridLayout(4,2));
		autoMetaData.add(new JLabel("File Size: "));
		autoMetaData.add(imageFileSizeInput);
		imageFileSizeInput.setEditable(false);
		
		autoMetaData.add(new JLabel("Dimensions: "));
		autoMetaData.add(imageDimensionInput);
		imageDimensionInput.setEditable(false);
		
		autoMetaData.add(new JLabel("Bit Depth: "));
		autoMetaData.add(imageBitDepthInput);
		imageBitDepthInput.setEditable(false);
		
		autoMetaData.add(new JLabel("Royalty Free: "));
		autoMetaData.add(imageHasRoyalties);
		
		metaData.setBorder(BorderFactory.createTitledBorder("Meta Data"));
		metaData.setLayout(new BorderLayout());
		
		metaData.add(userMetaData, BorderLayout.WEST);
		metaData.add(autoMetaData, BorderLayout.EAST);
		
		/* Main Panel Set up */
		main.setLayout(new BorderLayout());
		main.add(images, BorderLayout.NORTH);
		main.add(metaData, BorderLayout.CENTER);
		main.add(fileBrowser, BorderLayout.SOUTH);
		
		/* Get config file */
		configureClient(configFile);
		
		/* Swing House Keeping */
		setContentPane(main);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		//setResizable(false);
		pack();
		setVisible(true);
	}
	
	/** Configures the client to connect to a particular server */
	public void configureClient(File config){
		if(!config.exists()){	/* File doesn't exist so ask user for server and then store it to file */
			String server = "";
			while(server.equalsIgnoreCase("")){
				server = JOptionPane.showInputDialog("Please give the name of the Upload Server you wish to connect to as one could not be found\nPlease give in the form [host-name]/[ServiceName]\nFor example test-server.selfip.com/UploadService");
			}
			server = server.trim();
			serverName = server;
			
			/* Write configuration to file */
			try{
				BufferedWriter out = new BufferedWriter(new FileWriter(config));
				
				out.write("# Auto generated config file\n");
				out.write("upload-service=" + serverName + "\n");
				
				out.close();
			}catch (IOException e){
				e.printStackTrace();
			}
		}else{		/* File exists so just read it in a save it */
			try {
				BufferedReader read = new BufferedReader(new FileReader(config));
				/* Read until we find match to user name */
				String currentLine;
				while((currentLine = read.readLine()) != null){
					if(currentLine.contains("#")){
						
					}else{
						String[] configOption = currentLine.split("=");
						
						/* Figure out which option it is */
						if(configOption[0].equalsIgnoreCase("upload-service")){
							serverName = configOption[1];
						}
					}
				}
				read.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args){
		new UploadGUI(new File(".client_config"));
	}

	/** Method is called when the user interact with the buttons */
	public void actionPerformed(ActionEvent e) {
		JButton button = (JButton)e.getSource();
		
		if(button == openFile){
			openFile();
		}else if(button == browseForFile){
			browseForFile();
		}
	}
	
	/** Opens a file and creates a preview of the image, and it's various quality levels */
	private void openFile(){
		if(filePath.getText().equalsIgnoreCase("")){
			JOptionPane.showMessageDialog(this, "You must specify a file");
		}else{
			try{
				Thread compressionThread = new Thread(){
					public void run(){
						ProgressUpdate p = new ProgressUpdate(11);
						p.updateTask("Opening File");
						mainPreview.displayImage(JAI.create("fileload", filePath.getText()).getAsBufferedImage());
						p.updateTask("Getting meta data");
						populateMetaData();
						p.updateTask("Compressing Low Quality Preview");
						JPEGEncoderThread thread1 = new JPEGEncoderThread(mainPreview.getBufferedImage(), JPEGEncoderThread.LOW_QUALITY);
						p.updateTask("Compressing Good Quality Preview");
						JPEGEncoderThread thread2 = new JPEGEncoderThread(mainPreview.getBufferedImage(), JPEGEncoderThread.GOOD_QUALITY);
						p.updateTask("Compressing Fine Quality Preview");
						JPEGEncoderThread thread3 = new JPEGEncoderThread(mainPreview.getBufferedImage(), JPEGEncoderThread.FINE_QUALITY);
						p.updateTask("Compressing Pro Quality Preview");
						JPEGEncoderThread thread4 = new JPEGEncoderThread(mainPreview.getBufferedImage(), JPEGEncoderThread.PRO_QUALITY);
						
						/* Add previews to the display */
						p.updateTask("Displaying Low Quality Preview");
						preview1.displayImage(JAI.create("fileload", "tmp/Image0.jpg").getAsBufferedImage());
						p.updateTask("Displaying Good Quality Preview");
						preview2.displayImage(JAI.create("fileload", "tmp/Image1.jpg").getAsBufferedImage());
						p.updateTask("Displaying Fine Quality Preview");
						preview3.displayImage(JAI.create("fileload", "tmp/Image2.jpg").getAsBufferedImage());
						p.updateTask("Displaying Pro Quality Preview");
						preview4.displayImage(JAI.create("fileload", "tmp/Image3.jpg").getAsBufferedImage());
						p.updateTask("Compression Compete");
					}
				};
				compressionThread.start();
			}catch(Exception e){
				e.printStackTrace();
				JOptionPane.showMessageDialog(this, "Could not process file");
			}
		}
	}
	
	/** Populates the fields of the meta data display */
	private void populateMetaData(){
		imageFileSizeInput.setText((currentFile.length() / 1024)+"");
		imageDimensionInput.setText(mainPreview.getImageDimension().getWidth() + " x " + mainPreview.getImageDimension().getHeight());
		imageBitDepthInput.setText(mainPreview.getBitsPerPixel()+"");
	}
	
	/** Called when the user requests to browser their file system for an image */
	private void browseForFile(){
		/* Open the file browser */
		int returnVal = fileBrowsing.showOpenDialog(this);
		
		if(returnVal == JFileChooser.APPROVE_OPTION){		/* User selected a file */
			currentFile = fileBrowsing.getSelectedFile();
			updateFileBrowsing();
		}
	}
	
	/** Updates the file browsing panel when a user selects a new image */
	private void updateFileBrowsing(){
		filePath.setText(currentFile.getAbsolutePath());
	}
	
	public void swap(final ImageViewer preview){
		if(preview.isMain()){
			/* Check one more time */
			if(imageTitleInput.getText().equalsIgnoreCase("") | imageKeywordsInput.getText().equalsIgnoreCase("") | imageDescription.getText().equalsIgnoreCase("")){
				JOptionPane.showMessageDialog(this, "You must complete all meta data fields");
			}else{
				
				Thread uploadThread = new Thread(){
					public void run(){
						ProgressUpdate p = new ProgressUpdate(4);
						p.updateTask("Packing original Image");
						byte[] original = Util.fileToByteArray(currentFile);
						byte[] compressed;
						
						p.updateTask("Compressing Image");
						String compLevel = null;
						String royaltyFree = null;
						
						if(imageHasRoyalties.isSelected()){
							royaltyFree = "1";
						}else{
							royaltyFree = "0";
						}
						
						if(lowRadio.isSelected()){
							compressed = Util.fileToByteArray(new File("tmp/Image0.jpg"));
							compLevel = "1";
						}else if(goodRadio.isSelected()){
							compressed = Util.fileToByteArray(new File("tmp/Image1.jpg"));
							compLevel = "2";
						}else if(fineRadio.isSelected()){
							compressed = Util.fileToByteArray(new File("tmp/Image2.jpg"));
							compLevel = "3";
						}else{
							compressed = Util.fileToByteArray(new File("tmp/Image3.jpg"));
							compLevel = "4";
						}
						
						ImageUpload upload = new ImageUpload(imageTitleInput.getText(), imageDescription.getText(), imageKeywordsInput.getText(), imageDimensionInput.getText(), imageBitDepthInput.getText(), imageFileSizeInput.getText(), compLevel, royaltyFree, original, compressed);
						p.updateTask("Uploading Image");
						try{
							Registry reg = LocateRegistry.getRegistry(serverName.substring(0, serverName.indexOf("/")), 1099);
							System.out.println(reg.list()[0]);
							UploadService service = (UploadService)reg.lookup("rmi://" + serverName);
							service.uploadImage(upload);
						}catch(Exception e){
							e.printStackTrace();
						}
						p.updateTask("Upload Complete");	
					}
				};
				
				uploadThread.start();
			}
		}else{
			final ProgressUpdate p = new ProgressUpdate(7);
			
			Thread swapThread = new Thread(){
				public void run(){
					p.updateTask("Getting images");
					BufferedImage mainImage = mainPreview.getBufferedImage();
					BufferedImage otherImage = preview.getBufferedImage();
					
					p.updateTask("Getting ui components");
					JLabel l1 = mainPreview.getImageIdentifier();
					JLabel l2 = preview.getImageIdentifier();
					
					JRadioButton r1 = mainPreview.getRadioButton();
					JRadioButton r2 = preview.getRadioButton();
					
					p.updateTask("Swapping main image");
					mainPreview.displayImage(otherImage);
					
					mainImagePanel.remove(l1);
					mainPreview.setIdentifier(l2);
					mainImagePanel.add(l2, BorderLayout.NORTH);
					
					mainImagePanel.remove(r1);
					mainPreview.setRadioSelection(r2);
					mainImagePanel.add(r2, BorderLayout.SOUTH);
					
					p.updateTask("Swapping smaller image");
					preview.displayImage(mainImage);
					
					p.updateTask("Swapping preview components");
					preview.getParentPanel().remove(preview.getImageIdentifier());
					preview.setIdentifier(l1);
					preview.getParentPanel().add(l1, BorderLayout.NORTH);
	
					p.updateTask("Swapping main components");
					preview.remove(r2);
					preview.setRadioSelection(r1);
					preview.add(r1, BorderLayout.SOUTH);
					
					p.updateTask("Re-drawing interface");
					pack();
				}
			};
			
			swapThread.start();
		}
	}
}
